import "module-alias/register";
import "reflect-metadata";
import path from "path";
import express from "express";
import cookieParser from "cookie-parser";
import logger from "./src/config/loggers";
import { excludeUrlList } from "@/config/constant";
import { Request, Response, NextFunction } from "express";
import { Result, Check, Token, redis } from "@/utils";

import "express-async-errors";

import "@/Init";
import * as controllers from "./src/controllers";

const PORT = process.env.PORT;
const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use("/api/static", express.static("upload/xlsx"));
app.use(logger.accessLog);
app.use(logger.accessLogErr);

// 设置请求头过滤
app.all("*", function (req, res, next) {
   res.header("Access-Control-Allow-Credentials", "true");
   res.header("Access-Control-Allow-Origin", "*");
   res.header("Access-Control-Allow-Headers", "X-Requested-With");
   res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
   // res.header("Content-Type", "application/json;charset=utf-8");
   next();
});

/**验证 token
 * 不需要验证登陆信息的接口链接放入排除列表中
 * token必须包含在请求头(headers)中
 * token存在时效，超出失效将验证失败
 */
app.use(async function (req, res, next) {
   console.log("originalUrl", req.originalUrl);

   if (JSON.stringify(req.body) != "{}") console.table(req.body);
   if (JSON.stringify(req.query) != "{}") console.table(req.query);

   /** 部分接口排除验证 */
   if (excludeUrlList.includes(req.originalUrl)) return next();

   //token可能存在post请求和get请求
   const { token } = req.headers;
   // 当 token 不存在时
   if (!token) return res.send(Result.Error("身份验证失败，请重新登录"));

   const v = await Token.Verify(token);
   // token 解析成功
   if (v) {
      const userId = Token.Decrypt(token);
      if (!userId) return res.send(Result.Error("身份验证失败，请重新登录")); // 用户 id 解析失败

      // 从 redis 中读取缓存信息
      const userLocalStr = await redis.get(userId);

      // 未读取到信息
      if (!userLocalStr) return res.send(Result.Error("身份验证失败，请重新登录"));
      // 读取信息不为 JSON
      if (!Check.StringIsJSON(userLocalStr)) return res.send(Result.Error("身份验证失败，请重新登录"));

      const userLocal = JSON.parse(userLocalStr);
      // 当前 redis 中的 token 与接受的 token 不一致
      if (token != userLocal.token) return res.send(Result.Error("验证信息失效，请重新登录"));

      req.userId = userId;

      next();
   } else {
      res.send(Result.Error("身份验证失败，请重新登录"));
   }
});

// 导入路由
Object.entries(controllers).forEach(([key, value]) => {
   app.use(`/api/${key}`, value);
});

app.use(function (err: any, req: Request, res: Response, next: NextFunction) {
   console.log("error", err);
   if (err.message) {
      res.send(Result.Error());
   }

   next(err);
});

// catch 404 and forward to error handler
app.use(function (req, res, next) {
   res.status(404).send(Result.Error("Can not find"));
});

app.listen(PORT);
